---
layout: docs
page_title: 'Configuration Entry Kind: Service Splitter'
description: >-
  The service-splitter config entry kind controls how to split incoming Connect
  requests across different subsets of a single service (like during staged
  canary rollouts), or perhaps across different services (like during a v2
  rewrite or other type of codebase migration).
---

# Service Splitter

-> **v1.8.4+:** On Kubernetes, the `ServiceSplitter` custom resource is supported in Consul versions 1.8.4+.<br />
**v1.6.0+:** On other platforms, this config entry is supported in Consul versions 1.6.0+.

The `service-splitter` config entry kind (`ServiceSplitter` on Kubernetes) controls how to split incoming Connect
requests across different subsets of a single service (like during staged
canary rollouts), or perhaps across different services (like during a v2
rewrite or other type of codebase migration).

If no splitter config is defined for a service it is assumed 100% of traffic
flows to a service with the same name and discovery continues on to the
resolution stage.

## Interaction with other Config Entries

- Service splitter config entries are a component of [L7 Traffic
  Management](/docs/connect/l7-traffic).

- Service splitter config entries are restricted to only services that define
  their protocol as http-based via a corresponding
  [`service-defaults`](/docs/connect/config-entries/service-defaults) config
  entry or globally via
  [`proxy-defaults`](/docs/connect/config-entries/proxy-defaults) .

- Any split destination that specifies a different `Service` field and omits
  the `ServiceSubset` field is eligible for further splitting should a splitter
  be configured for that other service, otherwise resolution proceeds according
  to any configured
  [`service-resolver`](/docs/connect/config-entries/service-resolver).

## UI

Once a `service-splitter` is successfully entered, you can view it in the UI. Service routers, service splitters, and service resolvers can all be viewed by clicking on your service then switching to the _routing_ tab.

![screenshot of service splitter in the UI](/img/l7-routing/Splitter.png)

## Sample Config Entries

### Two subsets of same service

Split traffic between two subsets of the same service:

<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>

```hcl
Kind = "service-splitter"
Name = "web"
Splits = [
  {
    Weight        = 90
    ServiceSubset = "v1"
  },
  {
    Weight        = 10
    ServiceSubset = "v2"
  },
]
```

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceSplitter
metadata:
  name: web
spec:
  splits:
    - weight: 90
      serviceSubset: v1
    - weight: 10
      serviceSubset: v2
```

```json
{
  "Kind": "service-splitter",
  "Name": "web",
  "Splits": [
    {
      "Weight": 90,
      "ServiceSubset": "v1"
    },
    {
      "Weight": 10,
      "ServiceSubset": "v2"
    }
  ]
}
```

</CodeTabs>

### Two different services

Split traffic between two services:

<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>

```hcl
Kind = "service-splitter"
Name = "web"
Splits = [
  {
    Weight  = 50
    # will default to service with same name as config entry ("web")
  },
  {
    Weight  = 50
    Service = "web-rewrite"
  },
]
```

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceSplitter
metadata:
  name: web
spec:
  splits:
    - weight: 50
      # will default to service with same name as config entry ("web")
    - weight: 50
      service: web-rewrite
```

```json
{
  "Kind": "service-splitter",
  "Name": "web",
  "Splits": [
    {
      "Weight": 50
    },
    {
      "Weight": 50,
      "Service": "web-rewrite"
    }
  ]
}
```

</CodeTabs>

### Set HTTP Headers

Split traffic between two subsets with extra headers added so clients can tell
which version:

<CodeTabs tabs={[ "HCL", "Kubernetes YAML", "JSON" ]}>

```hcl
Kind = "service-splitter"
Name = "web"
Splits = [
  {
    Weight        = 90
    ServiceSubset = "v1"
    ResponseHeaders {
      Set {
        "X-Web-Version": "v1"
      }
    }
  },
  {
    Weight        = 10
    ServiceSubset = "v2"
    ResponseHeaders {
      Set {
        "X-Web-Version": "v2"
      }
    }
  },
]
```

```yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceSplitter
metadata:
  name: web
spec:
  splits:
    - weight: 90
      serviceSubset: v1
      responseHeaders:
        set:
          x-web-version: v1
    - weight: 10
      serviceSubset: v2
      responseHeaders:
        set:
          x-web-version: v2
```

```json
{
  "Kind": "service-splitter",
  "Name": "web",
  "Splits": [
    {
      "Weight": 90,
      "ServiceSubset": "v1",
      "ResponseHeaders": {
        "Set": {
          "X-Web-Version": "v1"
        }
      }
    },
    {
      "Weight": 10,
      "ServiceSubset": "v2",
      "ResponseHeaders": {
        "Set": {
          "X-Web-Version": "v2"
        }
      }
    }
  ]
}
```

</CodeTabs>

## Available Fields

<ConfigEntryReference
  keys={[
    {
      name: 'apiVersion',
      description: 'Must be set to `consul.hashicorp.com/v1alpha1`',
      hcl: false,
    },
    {
      name: 'Kind',
      description: {
        hcl: 'Must be set to `service-splitter`',
        yaml: 'Must be set to `ServiceSplitter`',
      },
    },
    {
      name: 'Name',
      description: 'Set to the name of the service being configured.',
      type: 'string: <required>',
      yaml: false,
    },
    {
      name: 'Namespace',
      type: `string: "default"`,
      enterprise: true,
      description:
        'Specifies the namespace to which the configuration entry will apply.',
      yaml: false,
    },
    {
      name: 'Partition',
      type: `string: "default"`,
      enterprise: true,
      description:
        'Specifies the admin partition to which the configuration entry will apply.',
      yaml: false,
    },
    {
      name: 'Meta',
      type: 'map<string|string>: nil',
      description:
        'Specifies arbitrary KV metadata pairs. Added in Consul 1.8.4.',
      yaml: false,
    },
    {
      name: 'metadata',
      children: [
        {
          name: 'name',
          description: 'Set to the name of the service being configured.',
        },
        {
          name: 'namespace',
          description:
            'If running Consul Open Source, the namespace is ignored (see [Kubernetes Namespaces in Consul OSS](/docs/k8s/crds#consul-oss)). If running Consul Enterprise see [Kubernetes Namespaces in Consul Enterprise](/docs/k8s/crds#consul-enterprise) for more details.',
        },
      ],
      hcl: false,
    },
    {
      name: 'Splits',
      type: 'array<ServiceSplit>',
      description:
        'Defines how much traffic to send to which set of service instances during a traffic split. The sum of weights across all splits must add up to 100.',
      children: [
        {
          name: 'weight',
          type: 'float32: 0',
          description:
            'A value between 0 and 100 reflecting what portion of traffic should be directed to this split. The smallest representable eight is 1/10000 or .01%',
        },
        {
          name: 'Service',
          type: 'string: ""',
          description: 'The service to resolve instead of the default.',
        },
        {
          name: 'ServiceSubset',
          type: 'string: ""',
          description: {
            hcl:
              "A named subset of the given service to resolve instead of one defined as that service's `DefaultSubset`. If empty the default subset is used.",
            yaml:
              "A named subset of the given service to resolve instead of one defined as that service's `defaultSubset`. If empty the default subset is used.",
          },
        },
        {
          name: 'Namespace',
          enterprise: true,
          type: 'string: ""',
          description:
            'The namespace to resolve the service from instead of the current namespace. If empty, the current namespace is used.',
        },
        {
          name: 'Partition',
          enterprise: true,
          type: 'string: ""',
          description:
            'The admin partition to resolve the service from instead of the current partition. If empty, the current partition is used.',
        },
        {
          name: 'RequestHeaders',
          type: 'HTTPHeaderModifiers: <optional>',
          description: `A set of [HTTP-specific header modification rules](/docs/connect/config-entries/service-router#httpheadermodifiers)
          that will be applied to requests routed to this split.
          This cannot be used with a \`tcp\` listener.`,
        },
        {
          name: 'ResponseHeaders',
          type: 'HTTPHeaderModifiers: <optional>',
          description: `A set of [HTTP-specific header modification rules](/docs/connect/config-entries/service-router#httpheadermodifiers)
          that will be applied to responses from this split.
          This cannot be used with a \`tcp\` listener.`,
        },
      ],
    },
  ]}
/>

## ACLs

Configuration entries may be protected by [ACLs](/docs/security/acl).

Reading a `service-splitter` config entry requires `service:read` on the resource.

Creating, updating, or deleting a `service-splitter` config entry requires
`service:write` on the resource and `service:read` on any other service referenced by
name in these fields:

- [`Splits[].Service`](#service)
